package com.lr.demo;

import java.io.IOException;
import java.io.Writer;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;

import com.lr.model.User;

//这个注解与testSessionAttributes方法中的  map.put("user", u);
//共同决定吧user放入session
//使用value属性     @SessionAttributes(value={"user"})
// @SessionAttributes(types={User.class})
@RequestMapping("/springMvc")	
@Controller
public class SpringMvcTest {
	
	public static String success = "success";
	
	
	/**
	 * 运行流程 ：
	 * 第一步:执行  @MoedlAttribute 注=注解修饰的方法，把数据放到map中
	 * 第二步:springMvc 从map中取出User对象 并把表单的请求参数赋给该user对象的对应属性
	 * 第三部：springMvc把上述对象传入目标参数
	 */
	
	
	/**
	 * 有@ModelAttribute 标记的方法  会在每个目标方法执行之前被spring 调用
	 */
	@ModelAttribute
	public void getUser(@RequestParam(value="id")Integer id,
			Map<String, Object> map){
		System.err.println("modelAttribute method");
		if(id!=null){
			User user = new User("llllll", 17, "1233333",null);
			user.setId(1);
			System.err.println("模拟从数据库中获去"+user.toString());
			map.put("user",user);
			/**
			 * 这个地放的 key 对应的是   
			 * 方法testModelAttribute(User abc)
			 * 参数类型    且   第一个字母变小写
			 */
		}else{
			System.err.println("调用：可能是冗余");
		}
	}
	@RequestMapping(value="testModelAttribute")
	public String testModelAttribute(User abc){
		System.err.println(abc.toString());
		return success;
	}
	
	/**
	 * 往session中放参数
	 * @sessionAttributes   只能放到类上 不能放到方法上
	 * 1、可以通过属性名指定需要放到会话中的属性值（使用value属性值）
	 * 2、还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中（使用types属性）
	 * 使用@sessionAttributes 与testModelAttribute这个方法会产生错误   之后会解决
	 */
	@RequestMapping(value="testSessionAttributes")
	public String testSessionAttributes(Map<String, Object> map){
		User u = new User("lr",1,"123333",null);
		map.put("user", u);
		return success;
	}
	//  testMap与testModelAndView  都是把数据放到request中去  
	/**	
	 * 目标方法可以添加Map（也可以是Model  或 ModelMap）类型参数
	 * 这个参数用于在页面上获取
	 */
	@RequestMapping(value="testMap")
	public String testMap(Map<String,Object> map){
		System.err.println(map.getClass().getName());
		map.put("name", Arrays.asList("li","lr"));
		return success;
	}
	/**
	 * 目标方法的返回值可以是ModelAndView类型
	 * 其中可以包含视图和返回数据（模型）信息
	 * springMVC 会把ModelAndView 中的数据放入到request域对象中去
	 */
	@RequestMapping(value="/testModelAndView")
	public ModelAndView testModelAndView(){
		ModelAndView modelAndView  = new ModelAndView(success);
		//添加返回数据到ModelAndView中
		modelAndView.addObject("time", new Date());
		return modelAndView;
	}
	
	/**
	 * 可以使用servle原生的API作为目标方法的参数 
	 * 具体支持类型有：
	 * 	HttpServletRequest
	 * 	HttpServletResponse
	 * 	java.security.Principal
	 * 	Locale
	 * 	InputStream
	 * 	OutputStream
	 *  Reader
	 *  Writer
	 * @throws IOException 
	 */
	@RequestMapping(value="testServletApi")
	public void testServletApi(HttpServletRequest request,HttpServletResponse response,Writer write) throws IOException{
		System.out.println("testServletApi:"+request+"---"+response);
		write.write("hello");
		//return success;
	}
	/**
	 * springMvc 会根据请求参数名 和 实体类的属性名进行自动匹配
	 * 	自动为该对象填充属性 
	 * 	支持级联属性
	 *  如 addr.province  addr.city等
	 */
	@RequestMapping("/testPojo")
	public String testPojo(User user){
		System.out.println(user.toString());
		return success;
	}
	
	/**
	 *	了解
	 */
	@RequestMapping("/testCookieValue")
	public String testCookieValue(@CookieValue(value="JSESSIONID")String sessionId){
		System.err.println("CookieValue:sessionId="+sessionId);
		return success;
	}
	/**
	 * 用法与@RequestParam  
	 * 作用：映射请求与头信息
	 */
	@RequestMapping("/testRequestHeader")
	public String testRequestHeader(@RequestHeader(value="Accept-Encoding") String encod){
		System.out.println("RequestHeader Accept-Encoding:"+encod);
		return success;
	}
	
	/**
	 * @RequesttParam 来映射请求参数
	 *  value  值即请求参数的参数名
	 *  required 该值是否必须 默认必须
	 *  defaultValue  请求参数默认值
	 */
	@RequestMapping(value="/testRequestParam")
	public String testRequestParam(@RequestParam(value="name")String name
			,@RequestParam(value="age",required=false,defaultValue="0")Integer age){
		System.out.println(name+":"+age);
		return success;
	}
	
	/**
	 * REST 风格的url
	 * CRUD  :
	 * 新增： /order post
	 * 修改 ：/order/1 put
	 * 获取 ：/order/1 get
	 * 删除： /order/1 delete
	 * 
	 * 如何发送put、delete请求   
	 * 1、需要配置org.springframework.web.filter.HiddenHttpMethodFilter
	 * 2、需要发送post请求
	 * 3、需要在发送post 请求是携带一个name="_method"的隐藏域  值为 DELETE或PUT
	 * 
	 * 在springMVC的目标方法中如何得到ID
	 * 使用@PathVariable注解
	 */
	
	@RequestMapping(value="/testRest/{id}",method=RequestMethod.PUT)
	public String testRestUpdate(@PathVariable("id")Integer id){
		System.err.println("REST PUT:"+id);
		return success;
	}
	@RequestMapping(value="/testRest/{id}",method=RequestMethod.DELETE)
	public String testRestDelete(@PathVariable("id")Integer id){
		System.err.println("REST DELETE:"+id);
		return success;
	}
	
	@RequestMapping(value="/testRest",method=RequestMethod.POST)
	public String testRest(){
		System.err.println("REST POST");
		return success;
	}
	@RequestMapping(value="/testRest/{id}",method=RequestMethod.GET)
	public String testRest(@PathVariable("id")Integer id){
		System.err.println("REST GET:"+id);
		return success;
	}
	
	/**
	 * 
	 * @Author	李瑞
	 * @param id
	 * @param name
	 * @return  String
	 * @Date	2016年5月17日
	 * 更新日志
	 * 2016年5月17日 李瑞  首次创建
	 * 
	 * @PathVariable 可以映射url中的占位符到目标方法的参数中
	 *
	 */
	@RequestMapping(value="/testPathVariable/{id}/{name}")
	public String testPathVariable(@PathVariable(value="id") String id,@PathVariable(value="name")String name){
		System.err.println("testPathVariable:"+id+"="+name);
		return success;
	}
	/**
	 * Ant形式的通配符   
	 * ?:匹配一个字符
	 * *：匹配任何字符  
	 * **:匹配多层目录
	 */
	@RequestMapping(value="/testAntPath/**/ant")
	public String testAntPath2(){
		
		return success;
	}
	@RequestMapping(value="/testAntPath/*/ant")
	public String testAntPath1(){
		
		return success;
	}
	/**
	 * @Author	李瑞
	 * @return  String
	 * @Date	2016年5月17日
	 * 更新日志
	 * 2016年5月17日 李瑞  首次创建
	 * 
	 * params headers  不常用  
	 *
	 */
	@RequestMapping(value="/testParamAndHeaders"
			,params={"name","age!=10"}
			,headers={"Accept-Language=zh-CN,zh;q=0.8"})
	public String testParamsAndHeaders(){
		return success;
	}
	/**
	 * @Author	李瑞
	 * @return  String
	 * @Date	2016年5月13日
	 * 更新日志
	 * 2016年5月13日 李瑞  首次创建
	 * 使用method属性来指定请求方式
	 * 如果前台是get请求则无法应答
	 */
	@RequestMapping(value="/testMethod" ,method=RequestMethod.POST)
	public String testMethod(){
		System.err.println("testMethod");
		return success;
	}
	/**
	 * @Author	李瑞
	 * @return  String
	 * @Date	2016年5月13日
	 * 更新日志
	 * 2016年5月13日 李瑞  首次创建
	 *
	 */
	@RequestMapping("/springMvcTest")
	public String springMvcTest(){
		System.err.println("springMvcTest");
		return "success";
	}

}
